function getCumulativeOffset( _element )
{
    var offset = {
        x: 0,
        y: 0
    };
    
    
    function core()
    {
        if ( _element.nodeName != "BODY" )
        {
            offset.x += _element.offsetLeft;
            offset.y += _element.offsetTop;
            
            _element = _element.offsetParent;
            core();
        }
    }
    
    core();
    return offset;
}

/*
Event.prototype.getX = function()
{
    var offsetX = 0;
    if ( window.scrollX || window.scrollY )
    {
        offsetX = parseInt( window.scrollX );
    }
    else if ( window.pageXOffset || window.pageYOffset )
    {
        offsetX = parseInt( window.pageXOffset );
    }
    
    return parseInt( this.clientX + offsetX );  
}

Event.prototype.getY = function()
{
    var offsetY = 0;
    if ( window.scrollX || window.scrollY )
    {
        offsetY = parseInt( window.scrollY );
    }
    else if ( window.pageXOffset || window.pageYOffset )
    {
        offsetY = parseInt( window.pageYOffset );
    }
    
    return parseInt( this.clientY );  
}
*/
jwContext.instance = null;

jwContext.getInstance = function()
{
    if ( !jwContext.instance )
        jwContext.instance = new jwContext();
        
    return jwContext.instance;        
}

function jwContext()
{
    this.container = document.createElement( 'DIV' );
    document.body.appendChild( this.container );
    
    this.focusElement = document.createElement( "INPUT" );
    this.focusElement.style.marginLeft = "-5000px";
    this.focusElement.style.position = "absolute";
    this.container.appendChild( this.focusElement );
    this.table = document.createElement( 'TABLE' );    
    this.container.appendChild( this.table );
    this.table.className = "jwContextMenu";
    
    this.table.setAttribute( "cellpadding", 0 );
    this.table.setAttribute( "cellspacing", 0 );
    
    this.tableBody = document.createElement( "TBODY" );
    
    this.table.appendChild( this.tableBody );
    
    var copy = this;
    
    if ( this.focusElement.addEventListener )
    {
        this.focusElement.addEventListener( "blur" , function( event ){ copy.hide.call( copy, event ); } , false );
        this.focusElement.addEventListener( "keydown", function( event ){ copy.EventListeners.handleKeyDown.call( copy, event ); }, false );
        this.table.addEventListener( "mouseover", function( event ){ copy.EventListeners.handleMouseOver.call( copy, event ); }, false );
        this.table.addEventListener( "mouseout", function( event ){ copy.EventListeners.handleMouseOut.call( copy, event ); }, false );
        this.table.addEventListener( "mousedown", function( event ){ copy.EventListeners.handleClick.call( copy, event ); }, false );     
    }
    else if( this.focusElement.attachEvent )
    {
        this.focusElement.attachEvent( "onblur" , function( event ){copy.hide.call( copy, event ); } ) ;
        this.focusElement.attachEvent( "onkeydown", function( event ){ copy.EventListeners.handleKeyDown.call( copy, event ); } );
        this.table.attachEvent( "onmouseover", function( event ){ copy.EventListeners.handleMouseOver.call( copy, event ); } );
        this.table.attachEvent( "onmouseout", function( event ){ copy.EventListeners.handleMouseOut.call( copy, event ); } );
        this.table.attachEvent( "onmousedown", function( event ){ copy.EventListeners.handleClick.call( copy, event ); } );           
    }    
    
    this.cells = new Array();
}

jwContext.prototype.buildUp = function( _data )
{
    while( this.tableBody.hasChildNodes() )
    {
        this.tableBody.removeChild( this.tableBody.firstChild );
    }
    
    delete this.cells;
    this.cells = new Array();
    
    for( var i = 0; i < _data.length; i++ )
    {
        var lastRow = document.createElement( "TR" );
        var lastTd = document.createElement( "TD" );
        
        this.tableBody.appendChild( lastRow );
        lastRow.appendChild( lastTd );
            
        lastTd.innerHTML = _data[i].label;
        lastTd.className = _data[i].css;
        
        _data[i].colIndex = 0;
        _data[i].rowIndex = i;
        
        this.cells.push( new jwCell( lastTd, _data[i] ) );
        this.cells[ this.cells.length - 1 ].action = _data[i].action;
    }
    return this;
}


jwContext.prototype.show = function( _event )
{
    this.container.style.position = "fixed";
    this.container.style.top = _event.clientY - -2 + "px";
    this.container.style.left = _event.clientX - -2 + "px";
    this.container.style.display = 'block';
    this.focusElement.focus();    
}

jwContext.prototype.hide = function( _event )
{
    this.container.style.display = 'none';
}

jwContext.prototype.highlight = function( _index, off )
{
    if ( off )
    {
        var cell = this.cells[ _index ];        
        cell.domElement.className = cell.domElement.className.replace( /\s.*?highlight/, "" );                
    }
    else
    {  
        if ( typeof( this.lastIndex ) != "undefined" )
        {
            //document.getElementById( 'debugx' ).innerHTML += this.lastIndex+" -> " + _index+"\n";
            this.highlight( this.lastIndex, true );
        }
        
        var cell = this.cells[ _index ];
        if( cell.domElement.className.search( "highlight") == -1 )
            cell.domElement.className += " highlight";
        
        this.lastIndex = _index;
    }
}

jwContext.prototype.executeAction = function()
{
    eval( this.cells[ this.lastIndex ].action );
}

jwContext.prototype.EventListeners =
{
    handleMouseOver : function( _event )
    {
        if( window.event && LastEvent )
        {
            _event.rowIndex = LastEvent.rowIndex;
            _event.colIndex = LastEvent.colIndex;
            _event.target = _event.srcElement;
        }
        
        if( _event.target.nodeName.search( /td/i ) > -1)
        {
            this.highlight( _event.rowIndex );
        }
    },
    handleMouseOut : function( _event )
    {
        if( window.event && LastEvent )
        {
            _event.rowIndex = LastEvent.rowIndex;
            _event.colIndex = LastEvent.colIndex;
            _event.target = _event.srcElement;
        }
        
        if ( _event.target.nodeName.search( /td/i ) > -1 )
        {
            this.highlight( _event.rowIndex, true );
        }
    },
    handleKeyDown : function( _event )
    {
        switch( _event.keyCode )
        {
            case 40:
                if( this.lastIndex < this.cells.length - 1 )
                    this.highlight( this.lastIndex + 1 );
                else
                    this.highlight( 0 );
            break;
            case 38:
                if( this.lastIndex > 0 )
                    this.highlight( this.lastIndex - 1 );
                else
                    this.highlight( this.cells.length - 1 );
            break;
            case 13:
                this.executeAction();
                this.focusElement.blur();
            break;
        }
    },
    handleClick : function( _event )
    {
        this.executeAction();
    }
}